package com.itheima.sms.aspect;

import com.itheima.pinda.context.BaseContextHandler;
import com.itheima.sms.entity.base.BaseEntity;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;

/**
 * 通过切面方式，自定义注解，实现实体基础数据的注入（创建者、创建时间、修改者、修改时间）
 */
@Component
@Aspect
@Slf4j
public class DefaultParamsAspect {
    @SneakyThrows
    @Before("@annotation(com.itheima.sms.annotation.DefaultParams)")
    public void beforeEvent(JoinPoint point) {
        // TODO 自动注入基础属性（创建者、创建时间、修改者、修改时间）
        log.info("=========================== point: {}", point);

        // 1.从ThreadLocal中获取当前用户登录的id, 这里的user默认就是0
        Long userId = BaseContextHandler.getUserId();

        // 2.获取到Controller方法的参数
        Object[] args = point.getArgs();
        // arg对于参数, 通常是实体对象, 例如SignatureEntity
        Arrays.stream(args)
                // 使用 arg instanceof BaseEntity判断 ?
                .filter(arg -> arg instanceof BaseEntity)
                .forEach(arg -> {
                    BaseEntity entity = ((BaseEntity) arg);
                    if (StringUtils.isBlank(entity.getId())) {
                        // id == null, 当前进行的是新增操作, 需要设置创建人createUser和创建时间createTime
                        entity.setCreateTime(LocalDateTime.now());
                        entity.setCreateUser(userId.toString());
                    }
                    // id != null, 当前操作是更新操作
                    entity.setUpdateTime(LocalDateTime.now());
                    entity.setUpdateUser(userId.toString());
                    arg = entity;
                });
    }

    /**
     * 获得方法对象
     *
     * @param classes class对象
     * @param name    方法的名字
     * @param types   参数类型列表
     * @return 与指定name和types匹配的Method对象
     */
    private Method getMethod(Class classes, String name, Class... types) {
        try {
            return classes.getMethod(name, types);
        } catch (NoSuchMethodException e) {
            return null;
        }
    }
}
